import gtk, gtk.glade
import os.path
from gats import Gats, Subscription, Show, default_conf_path

gladefile = os.path.dirname(__file__) + "/gats.glade"



# -- gtk helper functions --

def gtkTextColumn(name, editable=False, model=None): # pass model if you want default, first-column editing behavior enabled
    col = gtk.TreeViewColumn(name)
    col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
    
    renderer = gtk.CellRendererText()
    if editable:
        renderer.set_property('editable', True)
        if model: # we have to manually apply changes to the model (what the hell gtk)
            def cellEdited(renderer, path, new_text):
                model[path][0] = new_text
            renderer.connect('edited', cellEdited)
    
    col.pack_start(renderer, True)
    col.add_attribute(renderer, 'text', 0)
 
    return col

def gtkSelectedText(treeView):
    (listStore, it) = treeView.get_selection().get_selected()
    if it:
        return listStore.get_value(it,0)
    else:
        return None



class GtkGats (Gats):

    # -- initialization --

    def __init__(self, path_conf=default_conf_path):
        Gats.__init__(self, path_conf)
        self.glade = gtk.glade.XML(gladefile)
        
        # main window: subscription list
        tree_subs = self.glade.get_widget("tree_subs")
        tree_subs.set_model(gtk.ListStore(str))
        tree_subs.append_column(gtkTextColumn("Subscriptions"))
        tree_subs.connect("row_activated", self.sub_row_activated)
        tree_subs.connect("cursor-changed", self.changed_sub)
        
        # main window: buttons
        self.glade.get_widget("btn_sub_edit").connect("pressed", self.press_sub_edit)
        self.glade.get_widget("btn_sub_add").connect("pressed", self.press_sub_add)
        self.glade.get_widget("btn_sub_remove").connect("pressed", self.press_sub_remove)
        
        # editor: show list
        tree_shows = self.glade.get_widget("tree_shows")
        tree_shows.set_model(gtk.ListStore(str))
        tree_shows.append_column(gtkTextColumn("Shows"))
        tree_shows.connect("cursor-changed", self.changed_show)
        
        # editor: feeds list
        tree_feeds = self.glade.get_widget("tree_feeds")
        store_feeds = gtk.ListStore(str)
        tree_feeds.set_model(store_feeds)
        tree_feeds.append_column(gtkTextColumn("Feeds",True,store_feeds))
        tree_feeds.connect("cursor-changed", self.changed_feed)
        
        # editor: buttons
        self.glade.get_widget("radio_catalog").connect("toggled", self.changed_sub_type)
        self.glade.get_widget("manual_add").connect("pressed", self.press_feed_add)
        self.glade.get_widget("manual_remove").connect("pressed", self.press_feed_remove)
        self.glade.get_widget("btn_edit_ok").connect("pressed", self.press_edit_ok)
        self.glade.get_widget("btn_edit_cancel").connect("pressed", self.press_edit_cancel)
        
        # prevent destruction of windows
        self.glade.get_widget("dlog_edit").connect("delete-event", self.window_close)
        self.glade.get_widget("win_subs").connect("delete-event", self.window_close)
        
    # -- helpers/maintenance --
        
    def refresh_sub_tree(self):
        store = self.glade.get_widget("tree_subs").get_model()
        store.clear()
        for sub in self.subs:
            store.append([sub.name])

    def refresh_show_tree(self):
        store = self.glade.get_widget("tree_shows").get_model()
        store.clear()
        for name in sorted(self.shows):
            store.append([name])
    
    def edit_sub(self, sub):
    
        self.editing = sub  # store the subscription we're currently editing (None = new sub)
        self.refresh_show_tree()
        
        # clear feed list before population
        store_feeds = self.glade.get_widget("tree_feeds").get_model()
        store_feeds.clear()
    
        if sub is None or sub.fromCatalog:
            tree_shows = self.glade.get_widget("tree_shows")
            if sub is None: # no subscription: use first show
                iter_selected = tree_shows.get_model().get_iter_first()
            else: # find the correct row in the catalog list
                iter_selected = None
                iter = tree_shows.get_model().get_iter_first()
                while (iter):
                    if tree_shows.get_model().get_value(iter, 0) == sub.name:
                        iter_selected = iter
                        break
                    iter = tree_shows.get_model().iter_next(iter)
            
            # select the row
            tree_shows.get_selection().select_iter(iter_selected)
            tree_shows.scroll_to_cell(tree_shows.get_model().get_path(iter_selected))
            
            self.glade.get_widget("radio_catalog").set_active(True) # select the appropriate radio button
            self.changed_sub_type()                                 # .. and simulate the appropriate event
        else:
            self.glade.get_widget("entry_name").set_text(sub.name)
            store_feeds = self.glade.get_widget("tree_feeds").get_model()
            for feed in sub.feeds:
                store_feeds.append([feed.url])
            self.glade.get_widget("radio_manual").set_active(True)
            pass
    
        self.glade.get_widget("dlog_edit").present()


    # -- callbacks for "subscriptions" window --
    
    def press_sub_edit(self, widget):
        # which show are we editing?
        (store_subs, path) = self.glade.get_widget("tree_subs").get_selection().get_selected_rows()
        sub = self.subs[path[0][0]]
        
        self.edit_sub(sub)
        return True
        
    def sub_row_activated(self, widget, path, col):
        self.glade.get_widget("btn_sub_edit").pressed()
        return True

    def changed_sub(self, widget=None):
        haysel = self.glade.get_widget("tree_subs").get_selection().get_selected()[1] is not None
        self.glade.get_widget("btn_sub_edit"  ).set_sensitive(haysel)
        self.glade.get_widget("btn_sub_remove").set_sensitive(haysel)
        return False

    def press_sub_add(self, widget):
        self.edit_sub(None)
        return True

    def press_sub_remove(self, widget):
        (store_sub, paths) = self.glade.get_widget("tree_subs").get_selection().get_selected_rows()
        del self.subs[paths[0][0]] # remove selection from the controller's data...
        store_sub.remove(store_sub.get_iter(paths[0])) # ... and from the TreeView
        self.changed_sub() # for some reason this doesn't always get called
        self.save_conf()
        return True


    # -- callbacks for edit dialog --

    def changed_sub_type(self, widget=None):
        fromCatalog = self.glade.get_widget("radio_catalog").get_active()
        
        for n in ["tree_shows"]:
            self.glade.get_widget(n).set_sensitive(fromCatalog)
        for n in ["entry_name", "tree_feeds", "manual_add", "manual_remove"]:
            self.glade.get_widget(n).set_sensitive(not fromCatalog)
        
        # simulate changes in respective treeviews
        if fromCatalog:
            self.changed_show()
        else:
            self.changed_feed()
        
        return True
    
    def changed_show(self, widget=None):
        # populate the "manual" fields with catalog data
        show = self.shows[gtkSelectedText(self.glade.get_widget("tree_shows"))]
        self.glade.get_widget("entry_name").set_text(show.name)
        store_feeds = self.glade.get_widget("tree_feeds").get_model()
        store_feeds.clear()
        for feed in show.feeds:
            store_feeds.append([feed.url])
        return True

    def changed_feed(self, widget=None):
        self.glade.get_widget("manual_remove").set_sensitive(
            self.glade.get_widget("tree_feeds").get_selection().get_selected()[1] is not None
          )
    
    def press_feed_add(self, widget):
        tree_feeds = self.glade.get_widget("tree_feeds")
        tree_feeds.get_column(0).get_cell_renderers()[0].stop_editing(True)
        tree_feeds.get_column(0).get_cell_renderers()[0].stop_editing(False)
        
        # add a new (empty) feed URL row
        iter = tree_feeds.get_model().append([''])
        tree_feeds.set_cursor(tree_feeds.get_model().get_path(iter), tree_feeds.get_column(0), True)
        return True

    def press_feed_remove(self, widget):
        (store_feeds, iter) = self.glade.get_widget("tree_feeds").get_selection().get_selected()
        store_feeds.remove(iter)
        self.changed_feed() # workaround as in press_sub_remove
        return True

    def press_edit_ok(self, widget):
        if self.editing is None:
            new_sub = True
            self.editing = Subscription()
            self.subs.append(self.editing)
        else:
            new_sub = False
        
        self.editing.fromCatalog = self.glade.get_widget("radio_catalog").get_active()
        if self.editing.fromCatalog:
            self.editing.name = gtkSelectedText(self.glade.get_widget("tree_shows"))
        else:
            self.editing.name = self.glade.get_widget("entry_name").get_text()
            self.editing.feeds = []
            store_feeds = self.glade.get_widget("tree_feeds").get_model()
            iter = store_feeds.get_iter_first()
            while (iter):
                self.editing.feeds.append(Feed(store_feeds.get_value(iter,0)))
                iter = store_feeds.iter_next(iter)
        
        if new_sub:
            self.refresh_sub_tree()
        else:
            # apply name change to subscription list
            tree_subs = self.glade.get_widget("tree_subs")
            tree_subs.get_model().set_value(tree_subs.get_selection().get_selected()[1], 0, self.editing.name)
            # (avoiding the call to refresh_sub_tree helps preserve the view's selection *)
        
        self.glade.get_widget("dlog_edit").hide()
        self.save_conf()
        return True

    def press_edit_cancel(self, widget):
        self.glade.get_widget("dlog_edit").hide()
        return True

    def window_close(self, window, event):
        window.hide()
        return True


    # -- external interface --

    def show_subs(self): # display window for viewing and editing subscriptions
        self.refresh_sub_tree()
        self.changed_sub()
        self.glade.get_widget("win_subs").present()
    
